package com.abel.bigwater.dataserver.model.ewide

import com.abel.bigwater.data.BcdString
import com.abel.bigwater.model.JsonHelper
import com.alibaba.fastjson.annotation.JSONField
import io.netty.buffer.ByteBuf
import org.slf4j.LoggerFactory
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap

class TermSendData(_pduLen: Int = -1) : TermData(KmingDataType.TermSendData, _pduLen) {
    var frameCount: Int? = null

    var frameIndex: Int? = null

    var rowCount: Short? = null

    /**
     * 通道数 1 HEX 终端通道标识码的个数
     */
    var channelCount: Short? = null

    /**
     * 通道标识码 2 HEX 终端通道标识码
    数据 1 NC HEX 数据格式根据标通道识码判断
    ……
    数据 n NC HEX 数据格式根据通道标识码判断
     */
    var channelDataList = ArrayList<FrameRow>()

    override fun bufLength() = 1 + 2 + 2 + 1 + 1 + (rowCount ?: 0) * (7 + 5 * (channelCount ?: 0))

    override fun parseBuf(buf: ByteBuf): Boolean {
        buf.apply {
            assert(type == KmingDataType.findByCode(readUnsignedByte()))

            frameCount = readUnsignedShortLE()
            frameIndex = readUnsignedShortLE()
            rowCount = readUnsignedByte()
            channelCount = readUnsignedByte()

            for (i in 0 until rowCount!!) {
                channelDataList.add(FrameRow(channelCount).also { it.parseBuf(readBytes(it.bufLength())) })
            }
        }

        return true
    }

    override fun pack(buf: ByteBuf) {
        buf.alloc().buffer().apply {
            writeByte(type.code.toInt())

            writeShortLE(frameCount!!)
            writeShortLE(frameIndex!!)
            writeByte(rowCount!!.toInt())
            writeByte(channelCount!!.toInt())

            for (i in 0 until rowCount!!) {
                channelDataList[i].pack(this)
            }

            buf.writeBytes(this)
        }
    }

    override fun toString(): String {
        return "{frame:$frameIndex/$frameCount,data:${channelDataList.joinToString()}}"
    }
}

class FrameRow(var channelCount: Short?, _pduLen: Int = -1) : TermData(KmingDataType.TermDummy, _pduLen) {
    override fun bufLength() = 7 + 5 * channelCount!!

    override fun parseBuf(buf: ByteBuf): Boolean {
        assert(buf.readableBytes() == bufLength())
        assert(channelCount!! >= 0)

        startTimeStr = BcdString.create(buf, 7)

        for (i in 1..channelCount!!) {
            val code = buf.readUnsignedByte()
            val ch = KmingChannelType.findByCode(code)
            lgr.warn("channel code: ${code.toString(16)}")

            channelList.add(ch ?: KmingChannelType.DummyChannel)

            dataList.add(buf.readUnsignedIntLE())
        }

        return true
    }

    override fun pack(buf: ByteBuf) {
        buf.writeBytes(startTimeStr!!.hexArray)

        assert(channelCount?.toInt() == channelList.size)
        assert(channelCount?.toInt() == dataList.size)
        for (i in 0 until channelCount!!) {
            buf.writeByte(channelList[i].code.toInt())
            buf.writeIntLE(dataList[i].toInt())
        }
    }

    /**
     * 起始时间 6 BCD 终端采样时间：年-月-日-时-分-秒（注
    2）
     */
    var startTimeStr: BcdString? = null

    /**
     * 时间对象
     */
    @JSONField(format = JsonHelper.FULL_DATE_FORMAT)
    private var _startTime: Date? = null

    var startTime: Date?
        get() {
            _startTime = if (startTimeStr == null) null else startTimeStr!!.toFullYearTime()
            return _startTime
        }
        set(value) {
            _startTime = value
            startTimeStr = if (_startTime == null) null
            else fromFullYearTime(_startTime!!)
        }

    var channelList = ArrayList<KmingChannelType>()

    var dataList = ArrayList<Long>()

    /**
     * put channel to data in the map.
     */
    fun buildMap(): HashMap<KmingChannelType, Long> {
        val map = HashMap<KmingChannelType, Long>()
        for (i in 0 until channelCount!!) {
            map[channelList[i]] = dataList[i]
        }

        return map
    }

    companion object {
        private val lgr = LoggerFactory.getLogger(FrameRow::class.java)
    }
}